﻿extern alias tasks;

using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using CDude.Tools;

using ICSharpCode.SharpZipLib.Zip;

using Sce.Psm;
using scetasks = tasks.Sce.Psm;

namespace CDude.Vita
{
    internal partial class VCg_MainForm : Form
    {
        public const string LANGUAGE_DIR = "lang";
        private const string DELETION_PACKAGE = "stuff\\delete.psdp";
        private const string IL_SEARCH_NAME = "// =============== CLASS MEMBERS DECLARATION ===================\r\n\r\n";
        private const string IL_SEARCH_REFS = "\r\n.assembly extern Sce.PlayStation.Core\r\n";
        private readonly string TEMP_DIR = Path.Combine(Environment.CurrentDirectory, "VitaCOM_temp");
        public Language CurrentLanguage = null;
        public Config VCConfig = new Config();
        private object actionlock = new object();
        private PsmDeviceConnection connection = null;
        private ContextMenu contextmenu;
        private int deviceid = 0;
        private string install_inputpath = null;
        private string love = "";
        private DevicePlugNotifier notifier = null;
        private string pack_fullinputpath = null;
        private bool pack_isappdir = false;
        private string pack_outfilepath = null;
        private OperationInProgressForm progressform;
        private bool pack_converting = false;
        private readonly string ildasmpath;
        private readonly string ilasmpath;

        public VCg_MainForm()
        {
            CheckForIllegalCrossThreadCalls = false;

            notifier = new DevicePlugNotifier(this);

            InitializeComponent();

            if (VCConfig.Language != "default")
            {
                try
                {
                    ChangeLanguage(Path.Combine(VCg_MainForm.LANGUAGE_DIR, "vclang_" + VCConfig.Language + ".xml"));

                    if (File.Exists(Path.Combine(VCg_MainForm.LANGUAGE_DIR, "vclang_" + VCConfig.Language + ".png")))
                        langButton.Image = Image.FromFile(Path.Combine(VCg_MainForm.LANGUAGE_DIR, "vclang_" + VCConfig.Language + ".png"));
                }
                catch
                {
                }
            }
            else
                langButton.Image = Properties.Resources.uk_flag;

            randomLabel.Text = SelectLangString("Downloading random text...", "DownloadingText");

            ilasmpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Microsoft.NET\\Framework\\v2.0.50727\\ilasm.exe");
            //ildasmpath = Path.Combine(getProgramFilesx86Path(), "Microsoft SDKs\\Windows\\v8.0A\\bin\\NETFX 4.0 Tools\\ildasm.exe");
            ildasmpath = Path.Combine(Environment.CurrentDirectory, "stuff\\ildasm.exe");

            new Task(() =>
            {
                RandomText randomtext = GetRandomText();
                randomLabel.Font = new Font(randomLabel.Font.SystemFontName, (float)randomtext.FontSize);
                randomLabel.Text = randomtext.Text;
            }).Start();

            progressform = new OperationInProgressForm(CurrentLanguage);
            progressform.Owner = this;

            pack_encryptionTypeBox.SelectedIndex = 0;
            if (!File.Exists(Path.Combine(getProgramFilesx86Path(), "MSBuild\\Sce\\Sce.Psm.Tasks.dll"))) pack_encryptionTypeBox.Enabled = false;

            MenuItem menu_restore = new MenuItem(SelectLangString("Restore", "Restore")) { Enabled = false };
            MenuItem menu_move = new MenuItem(SelectLangString("Move", "Move")) { Enabled = false };
            MenuItem menu_size = new MenuItem(SelectLangString("Size", "Size")) { Enabled = false };
            MenuItem menu_minimize = new MenuItem(SelectLangString("Minimize", "Minimize"), minimizeButton_Click);
            MenuItem menu_maximize = new MenuItem(SelectLangString("Maximize", "Maximize")) { Enabled = false };
            MenuItem menu_seperator = new MenuItem("-");
            MenuItem menu_close = new MenuItem(SelectLangString("Close", "Close"), closeButton_Click, Shortcut.AltF4) { DefaultItem = true };
            contextmenu = new ContextMenu(new MenuItem[] { menu_restore, menu_move, menu_size, menu_minimize, menu_maximize, menu_seperator, menu_close });

            titleBarText.Parent = titleBar;

            Bitmap smallicon = Icon.ExtractAssociatedIcon(System.Windows.Forms.Application.ExecutablePath).ToBitmap();
            titleBarIcon.Image = smallicon;

            versionLabel.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();

            notifier.DeviceChanged += onDeviceChanged;
            notifier.NoDataDeviceChanged += onNoDataDeviceChanged;
            updateDeviceList(true);
        }

        private PsmDevice[] devices { get { return PsmDevice.ListDevices(); } }

        #region Device List

        private void connectButton_Click(object sender, EventArgs e)
        {
            deviceid = deviceList.SelectedIndex;

            connectButton.Enabled = false;
            toggleDeviceList();

            setStatusText(SelectLangString("Connecting to device {0}...", "Connecting"), deviceid.ToString());
            if (devices.Length == 0 || deviceid > devices.Length || !devices[deviceid].Online)
            {
                setStatusText(SelectLangString("Device {0} is offline! Please start the PS Mobile Dev Assistant on the device and make sure the device is not asleep.", "ConnectOffline"), deviceid.ToString());
                toggleDeviceList();
                updateDeviceList(false);
                return;
            }

            new Task(() =>
            {
                try
                {
                    connection = devices[deviceid].Connect();
                    setStatusText(SelectLangString("Connected to device {0}!", "Connected"), deviceid.ToString());
                    toggleActions();
                    toggleDisconnectButtons();
                }
                catch
                {
                    setStatusText(SelectLangString("Could not connect to device {0}!", "CouldNotConnect"), deviceid.ToString());
                    toggleDeviceList();
                    connectButton.Enabled = true;
                    updateDeviceList(false);
                }
            }).Start();
        }

        private void deviceList_SelectedIndexChanged(object sender, EventArgs e)
        {
            onChangedIndex();
        }

        private void disconnect(bool showstatus)
        {
            new Task(() =>
            {
                toggleDisconnectButtons();
                try
                {
                    connection.Disconnect();
                }
                catch { }
                finally
                {
                    toggleDeviceList();
                    toggleActions();
                    if (showstatus) setStatusText(SelectLangString("Disconnected!", "Disconnected"));
                    updateDeviceList(false);
                    if (devices.Length > 0 && devices.Length >= deviceid && devices[deviceList.SelectedIndex].Online)
                        connectButton.Enabled = true;
                }
            }).Start();
        }

        private void disconnectButton_Click(object sender, EventArgs e)
        {
            disconnect(true);
        }

        private void killButton_Click(object sender, EventArgs e)
        {
            new Task(() =>
            {
                toggleDisconnectButtons();
                try
                {
                    connection.KillRunningApps();
                }
                catch { }
                finally
                {
                    toggleDeviceList();
                    toggleActions();
                    setStatusText(SelectLangString("Killed PSM app!", "ClosedPSM"));
                    updateDeviceList(false);
                }
            }).Start();
        }

        private void onChangedIndex()
        {
            if (deviceList.SelectedIndex != -1 && devices.Length > 0 && devices.Length >= deviceid && devices[deviceList.SelectedIndex].Online)
                connectButton.Enabled = true;
            else
                connectButton.Enabled = false;
        }

        private void onDeviceChanged(object sender, DevicePlugEventArgs e)
        {
            if (connection != null && (!e.Added || !connection.IsValid))
            {
                disconnect(true);
                updateDeviceList(false);
            }
            else if (connection == null || !connection.IsValid)
                updateDeviceList(true);
        }

        private void onNoDataDeviceChanged(object sender, EventArgs e)
        {
            Thread.Sleep(500);
            if (connection != null && (devices.Length > 0 && deviceid <= devices.Length && !devices[deviceid].Online || !connection.IsValid))
            {
                disconnect(true);
                updateDeviceList(false);
            }
            else if (connection == null)
            {
                connectButton.Enabled = false;
                updateDeviceList(true);
            }
        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            updateDeviceList(true);
        }

        private void updateDeviceList(bool showstatus)
        {
            int previousselection = deviceList.SelectedIndex;
            if (showstatus)
                setStatusText(SelectLangString("Getting device list...", "GettingDevList"));

            deviceList.SelectedItem = null;
            deviceList.Items.Clear();
            for (int i = 0; i < devices.Length; i++)
            {
                string onlinetext = SelectLangString("online", "online");
                if (!devices[i].Online) onlinetext = SelectLangString("offline", "offline");
                deviceList.Items.Add(SelectLangString("Device", "Device") + " #" + i + ": " + devices[i].Type + " \"" + devices[i].Name + "\" " + devices[i].Guid + " (" + onlinetext + ")");
            }

            if (devices.Length == 0)
            {
                if (showstatus)
                    setStatusText(SelectLangString("No devices connected!", "NoDevsConnected"));
            }
            else
            {
                if (deviceList.SelectedIndex == -1)
                {
                    if (deviceList.Items.Count > 0)
                        deviceList.SelectedIndex = 0;
                }
                else
                    deviceList.SelectedIndex = previousselection;

                if (showstatus)
                    setStatusText(SelectLangString("Got device list!", "GotDevList"));
            }
        }

        #endregion Device List

        #region Actions

        #region Install

        private void install(string appname, bool deleteeverything)
        {
            if (breakOut()) return;
            if (deleteeverything)
            {
                if (File.Exists(DELETION_PACKAGE))
                    install_inputpath = DELETION_PACKAGE;
                else
                {
                    MessageBox.Show(SelectLangString("Deletion package not found!", "DeletionPackageNotFound"));
                    return;
                }
            }
            else if (strArrContainsNull(install_inputPackagePath.Text, install_desiredAppName.Text)) return;

            lock (actionlock)
            {
                toggleProgressForm();
                Task installertask = new Task(() =>
                {
                    try
                    {
                        connection.InstallApp(install_inputpath, appname);
                        if (!deleteeverything)
                            setStatusText(SelectLangString("Installed {0}! You may need to restart the dev assistant for changes to show up.", "Installed"), appname);
                        else
                        {
                            connection.UninstallApp("Documents");
                            connection.UninstallApp("System");
                            connection.UninstallApp("Temp");
                            setStatusText("All apps have been deleted! You may need to restart the development assistant for changes to show up.", "Deleted", appname);
                        }
                        toggleProgressForm();
                    }
                    catch (Exception ex)
                    {
                        if (GlobalTools.SaveException(ex))
                            setStatusText(SelectLangString("The operation could not be completed! Please send error_log_gui.txt to celcodioc@gmail.com", "OpNotCompleted"));
                    }
                });

                if (!deleteeverything)
                    setStatusText(SelectLangString("Installing {0}...", "Installing"), appname);
                else
                    setStatusText(SelectLangString("Deleting all apps...", "Deleting"), appname);

                installertask.Start();
                new Task(() => { verifyWorkingDevices(ref installertask); }).Start();
            }
        }

        private void install_desiredAppName_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && install_DoButton.Enabled)
                install(install_desiredAppName.Text, false);
        }

        private void install_DoButton_Click(object sender, EventArgs e)
        {
            install(install_desiredAppName.Text, false);
        }

        private void install_selectPackageButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog o = new OpenFileDialog();
            o.Filter = "PS Mobile Packages|*.psdp";
            o.Title = SelectLangString("Select Package:", "SelectPackage");
            DialogResult r = o.ShowDialog();

            if (r == DialogResult.OK)
            {
                install_inputpath = o.FileName;
                install_inputPackagePath.Text = o.SafeFileName;
            }
        }

        #endregion Install

        #region Launch

        private void launch()
        {
            if (breakOut()) return;
            if (strArrContainsNull(launch_appName.Text)) return;
            appOutputBox.Clear();
            lock (actionlock)
            {
                toggleProgressForm();
                Task launchertask = new Task(() =>
                {
                    connection.LaunchApp(launch_appName.Text, launch_debugCheck.Checked, launch_profileCheck.Checked, launch_keepnetCheck.Checked, launch_args.Text);
                    if (launch_displayOutputCheck.Checked)
                        PsmDevice.SetConsoleCallback(new PsmDeviceConsoleCallback(new TextBoxWriter(appOutputBox).WriteLine));
                    else
                        PsmDevice.SetConsoleCallback(null);
                    setStatusText(SelectLangString("Launched {0}!", "Launched"), launch_appName.Text);
                    toggleProgressForm();
                    Thread.Sleep(250);
                    if (!launch_keepnetCheck.Checked) disconnect(false);
                });
                setStatusText(SelectLangString("Launching {0}...", "Launching"), launch_appName.Text);
                launchertask.Start();
                new Task(() => { verifyWorkingDevices(ref launchertask); }).Start();
            }
        }

        private void launch_appName_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && launch_DoButton.Enabled)
                launch();
        }

        private void launch_argsBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && launch_DoButton.Enabled)
                launch();
        }

        private void launch_displayOutputCheck_CheckedChanged(object sender, EventArgs e)
        {
            if (launch_displayOutputCheck.Checked)
                launch_keepnetCheck.Checked = true;

            launch_keepnetCheck.Enabled = !launch_keepnetCheck.Enabled;
        }

        private void launch_DoButton_Click(object sender, EventArgs e)
        {
            launch();
        }

        #endregion Launch

        #region Pack

        private void pack()
        {
            if (strArrContainsNull(pack_inputFolderPath.Text, pack_outputPackagePath.Text)) return;
            string suffix = null;

            if (pack_isappdir)
                suffix = "\\..";

            lock (actionlock)
            {
                toggleProgressForm();

                if (!pack_converting)
                {
                    Task packertask = new Task(() =>
                    {
                        try
                        {
                            if (pack_encryptionTypeBox.SelectedIndex > 0)
                            {
                                if (Directory.Exists(TEMP_DIR))
                                    Directory.Delete(TEMP_DIR, true);

                                if (!Directory.Exists(TEMP_DIR))
                                    Directory.CreateDirectory(TEMP_DIR);

                                string[] filestopack = Directory.GetFiles(pack_fullinputpath + suffix, "*.*", SearchOption.AllDirectories);
                                string edatapath = Path.Combine(TEMP_DIR, "Application\\edata.list");
                                if (!Directory.Exists(Path.Combine(TEMP_DIR, "Application")))
                                    Directory.CreateDirectory(Path.Combine(TEMP_DIR, "Application"));
                                StreamWriter writer = new StreamWriter(edatapath, true);
                                for (int i = 0; i < filestopack.Length; i++)
                                {
                                    string outpath = Path.Combine(TEMP_DIR, filestopack[i].Remove(0, (pack_fullinputpath + suffix).Length + 1));
                                    string extension = Path.GetExtension(filestopack[i]);
                                    string name = Path.GetFileName(filestopack[i]);
                                    if ((((extension != ".cgx") && (extension != ".exe")) && (extension != ".dll")) && (((name == "app.info")) || (((name == "app.cfg") || (name == "osc.cfg")) || (extension == ".mdb"))))
                                    {
                                        File.Copy(filestopack[i], outpath, true);
                                        writer.WriteLine(name);
                                        scetasks.Edata.Encrypt(filestopack[i], outpath, TEMP_DIR, (scetasks.ScePsmEdataType)Enum.Parse(typeof(scetasks.EdataType), (string)pack_encryptionTypeBox.SelectedItem), "", 0, "", 0);
                                    }
                                }
                                writer.Close();
                                PsmDevice.CreatePackage(pack_outfilepath, TEMP_DIR);
                            }
                            else
                                PsmDevice.CreatePackage(pack_outfilepath, pack_fullinputpath + suffix);
                            setStatusText(SelectLangString("Packed {0}!", "Packed"), pack_outputPackagePath.Text);
                        }
                        catch (Exception ex)
                        {
                            if (GlobalTools.SaveException(ex))
                                setStatusText(SelectLangString("The operation could not be completed! Please send error_log_gui.txt to celcodioc@gmail.com", "OpNotCompleted"));
                        }
                        finally
                        {
                            if (Directory.Exists(TEMP_DIR))
                                Directory.Delete(TEMP_DIR, true);
                            toggleProgressForm();
                        }
                    });
                    setStatusText(SelectLangString("Packing {0}...", "Packing"), pack_outputPackagePath.Text);
                    packertask.Start();
                }
                else
                {
                    Task convertertask = new Task(() =>
                    {
                        try
                        {
                            if (Directory.Exists(TEMP_DIR))
                                Directory.Delete(TEMP_DIR, true);

                            if (!Directory.Exists(TEMP_DIR))
                                Directory.CreateDirectory(TEMP_DIR);

                            new FastZip().ExtractZip(pack_fullinputpath, TEMP_DIR, "");

                            #region Convert Assemblies

                            if (!File.Exists(TEMP_DIR + "\\Application\\pssapp.exe"))
                            {
                                setStatusText(SelectLangString("No EXE found in input package!", "NoEXEPackage"));
                                return;
                            }

                            string exeassemblyname = convertAssembly("pssapp.exe", "app.exe"); //convert exe

                            //convert libraries
                            string[] filestoconvert = Directory.GetFiles(TEMP_DIR + "\\Application\\", "*.dll", SearchOption.AllDirectories);
                            for (int i = 0; i < filestoconvert.Length; i++)
                            {
                                string filename = Path.GetFileName(filestoconvert[i]);
                                convertAssembly(filename, filename);
                            }

                            #endregion


                            #region Convert app.cfg

                            string[] cfgfile;

                            if (File.Exists(TEMP_DIR + "\\Application\\app.cfg"))
                            {
                                cfgfile = File.ReadAllLines(TEMP_DIR + "\\Application\\app.cfg");



                                AppXml xmlfile = new AppXml(exeassemblyname);

                                for (int i = 0; i < cfgfile.Length; i++)
                                {
                                    if (cfgfile[i].IndexOf(':') != -1)
                                    {
                                        string[] pair = cfgfile[i].Split(':');
                                        pair[0] = pair[0].Trim();
                                        pair[1] = pair[1].Trim();

                                        switch (pair[0])
                                        {
                                            case "resource_heap_size":
                                                xmlfile.resource_heap_size = pair[1];
                                                break;

                                            case "managed_heap_size":
                                                xmlfile.managed_heap_size = pair[1];
                                                break;

                                            case "gamepad":
                                                if (pair[1] == "true")
                                                    xmlfile.feature_list += "		<feature value=\"GamePad\" />\n";
                                                break;

                                            case "touch":
                                                if (pair[1] == "true")
                                                    xmlfile.feature_list += "		<feature value=\"Touch\" />\n";
                                                break;

                                            case "motion":
                                                if (pair[1] == "true")
                                                    xmlfile.feature_list += "		<feature value=\"Motion\" />\n";
                                                break;
                                        }
                                    }
                                }

                                xmlfile.SaveInfo(TEMP_DIR + "\\Application\\");

                                File.Delete(TEMP_DIR + "\\Application\\app.cfg");
                            }

                            #endregion


                            #region Cleanup and edata.list

                            //create empty edata list
                            File.Create(TEMP_DIR + "\\Application\\edata.list").Close();

                            //remove old Sony DLLs one by one to avoid deleting user content
                            File.Delete(TEMP_DIR + "\\Application\\Sce.Pss.Core.dll");
                            File.Delete(TEMP_DIR + "\\Application\\Sce.Pss.HighLevel.GameEngine2D.dll");
                            File.Delete(TEMP_DIR + "\\Application\\Sce.Pss.HighLevel.Model.dll");
                            File.Delete(TEMP_DIR + "\\Application\\Sce.Pss.HighLevel.Physics2D.dll");
                            File.Delete(TEMP_DIR + "\\Application\\Sce.Pss.HighLevel.UI.dll");

                            #endregion


                            #region Pack files

                            PsmDevice.CreatePackage(pack_outfilepath, TEMP_DIR);

                            #endregion


                            setStatusText(SelectLangString("Converted {0}!", "Converted"), pack_outputPackagePath.Text);
                        }
                        catch (Exception ex)
                        {
                            if (GlobalTools.SaveException(ex))
                                setStatusText(SelectLangString("The operation could not be completed! Please send error_log_gui.txt to celcodioc@gmail.com", "OpNotCompleted"));
                        }
                        finally
                        {
                            if (Directory.Exists(TEMP_DIR))
                                Directory.Delete(TEMP_DIR, true);
                            toggleProgressForm();
                        }
                    });
                    setStatusText(SelectLangString("Converting {0}...", "Converting"), pack_outputPackagePath.Text);
                    convertertask.Start();
                }
            }
        }

        private void pack_DoButton_Click(object sender, EventArgs e)
        {
            pack();
        }


        private void pack_SwitchButton_Click(object sender, EventArgs e)
        {
            if (!File.Exists(ilasmpath) || !File.Exists(ildasmpath))
            {
                MessageBox.Show(SelectLangString("No ILASM/ILDASM was found. Visual Studio 2010 or 2012 is required to convert packages.", "NoILTools"), SelectLangString("Error", "Error") + " – VitaCOMgui", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            pack_converting = !pack_converting;

            if (!pack_converting)
            {
                pack_selectFolderButton.Text = SelectLangString("Select input folder", "Select_input_folder");
                packBox.Text = SelectLangString("Create Package", "Create_Package");
                pack_DoButton.Text = SelectLangString("PACK!", "PACK");
                pack_SwitchButton.Text = SelectLangString("Switch to converting", "Switch_to_converting");
            }
            else
            {
                pack_selectFolderButton.Text = SelectLangString("Select input file", "Select_input_file");
                packBox.Text = SelectLangString("Convert Package", "Convert_Package");
                pack_DoButton.Text = SelectLangString("CONVERT!", "CONVERT");
                pack_SwitchButton.Text = SelectLangString("Switch to packing", "Switch_to_packing");
            }

            pack_encryptionTypeLabel.Visible = !pack_converting;
            pack_encryptionTypeBox.Visible = !pack_converting;
        }

        private void pack_selectFolderButton_Click(object sender, EventArgs e)
        {
            if (!pack_converting)
            {
                FolderBrowserDialog folderdialog = new FolderBrowserDialog();
                folderdialog.Description = SelectLangString("Select the folder containing the app:", "SelectAppFolder");
                folderdialog.ShowNewFolderButton = false;
                DialogResult result = folderdialog.ShowDialog();

                if (result == DialogResult.OK)
                {
                    bool hasexe = true;

                    if (!File.Exists(folderdialog.SelectedPath + "\\app.exe") && !File.Exists(folderdialog.SelectedPath + "\\Application\\app.exe"))
                    {
                        DialogResult exeresult = MessageBox.Show(SelectLangString("No executable was found. Continue?", "NoEXE"), SelectLangString("Warning", "Warning") + " – VitaCOMgui", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                        if (exeresult == DialogResult.Yes)
                        {
                            hasexe = false;
                            pack_isappdir = true;
                        }
                        else
                        {
                            pack_isappdir = false;
                            return;
                        }
                    }

                    pack_isappdir = hasexe && File.Exists(folderdialog.SelectedPath + "\\app.exe");

                    pack_fullinputpath = folderdialog.SelectedPath;
                    pack_inputFolderPath.Text = folderdialog.SelectedPath.Replace("/", "\\").Substring(folderdialog.SelectedPath.LastIndexOf("\\") + 1);
                }
            }
            else
            {
                OpenFileDialog open = new OpenFileDialog();
                open.Filter = "Old PS Suite Packages|*.psspac";
                open.Title = SelectLangString("Select input file:", "Select_input_file");
                DialogResult result = open.ShowDialog();

                if (result == DialogResult.OK)
                {
                    pack_fullinputpath = open.FileName;
                    pack_inputFolderPath.Text = Path.GetFileName(open.FileName);
                }
            }
        }

        private void pack_selectOutputButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();
            save.Filter = "PS Mobile Packages|*.psdp";
            save.Title = SelectLangString("Type output file:", "TypeOutputFile");
            DialogResult result = save.ShowDialog();

            if (result == DialogResult.OK)
            {
                if (!pack_converting && !strArrContainsNull(pack_fullinputpath) && save.FileName.Contains(pack_fullinputpath))
                {
                    MessageBox.Show(SelectLangString("You cannot save the .psdp in the input folder or one of its subdirectories.", "CannotSaveThere"), SelectLangString("Warning", "Warning") + " – VitaCOMgui");
                    return;
                }
                pack_outfilepath = save.FileName;
                pack_outputPackagePath.Text = Path.GetFileName(save.FileName);
            }
        }

        #endregion Pack

        #region Uninstall

        private void uninstall()
        {
            if (breakOut()) return;
            if (strArrContainsNull(uninstall_appName.Text)) return;

            lock (actionlock)
            {
                toggleProgressForm();
                Task uninstallertask = new Task(() =>
                {
                    connection.UninstallApp(uninstall_appName.Text);
                    setStatusText(SelectLangString("Uninstalled {0}! You may need to restart the development assistant for changes to show up.", "Uninstalled"), uninstall_appName.Text);
                    toggleProgressForm();
                });
                setStatusText(SelectLangString("Uninstalling {0}...", "Uninstalling"), uninstall_appName.Text);
                uninstallertask.Start();
                new Task(() => { verifyWorkingDevices(ref uninstallertask); }).Start();
            }
        }

        private void uninstall_appName_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && uninstall_DoButton.Enabled)
                uninstall();
        }

        private void uninstall_DeleteEverythingButton_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show(SelectLangString("You are about to erase all your apps.\nDo you want to continue?", "DeleteButtonMessage"), SelectLangString("Warning", "Warning") + " – VitaCOMgui", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (result == DialogResult.Yes)
                install("", true);
        }

        private void uninstall_DoButton_Click(object sender, EventArgs e)
        {
            uninstall();
        }

        #endregion Uninstall

        #endregion Actions

        #region Misc

        internal void ChangeLanguage(string path)
        {
            this.CurrentLanguage = new Language(path);

            this.connectButton.Text = CurrentLanguage.Strings.Connect;
            this.disconnectButton.Text = CurrentLanguage.Strings.Disconnect;
            this.killButton.Text = CurrentLanguage.Strings.Kill_PSM;
            this.refreshButton.Text = CurrentLanguage.Strings.Refresh;

            this.installBox.Text = CurrentLanguage.Strings.Install_Application;
            this.install_selectPackageButton.Text = CurrentLanguage.Strings.Select_File;
            this.install_desiredAppNameLabel.Text = CurrentLanguage.Strings.Desired_app_name;
            this.install_DoButton.Text = CurrentLanguage.Strings.INSTALL;

            this.uninstallBox.Text = CurrentLanguage.Strings.Uninstall_Application;
            this.uninstall_appNameLabel.Text = CurrentLanguage.Strings.App_name;
            this.uninstall_DeleteEverythingButton.Text = CurrentLanguage.Strings.DeleteAllApps;
            this.uninstall_DoButton.Text = CurrentLanguage.Strings.UNINSTALL;

            this.launchBox.Text = CurrentLanguage.Strings.Launch_Application;
            this.launch_appNameLabel.Text = CurrentLanguage.Strings.App_name;
            this.launch_argsLabel.Text = CurrentLanguage.Strings.Arguments;
            this.launch_debugCheck.Text = CurrentLanguage.Strings.Debug;
            this.launch_profileCheck.Text = CurrentLanguage.Strings.Profile;
            this.launch_keepnetCheck.Text = CurrentLanguage.Strings.Keep_device_connection;
            this.launch_displayOutputCheck.Text = CurrentLanguage.Strings.Display_output;
            this.launch_DoButton.Text = CurrentLanguage.Strings.LAUNCH;

            this.packBox.Text = CurrentLanguage.Strings.Create_Package;
            this.pack_selectFolderButton.Text = CurrentLanguage.Strings.Select_input_folder;
            this.pack_selectOutputButton.Text = CurrentLanguage.Strings.Select_output_file;
            this.pack_encryptionTypeLabel.Text = CurrentLanguage.Strings.Encryption_type;
            this.pack_encryptionTypeBox.Items[0] = CurrentLanguage.Strings.None;
            this.pack_SwitchButton.Text = CurrentLanguage.Strings.Switch_to_converting;
            this.pack_DoButton.Text = CurrentLanguage.Strings.PACK;

            this.outputBox.Text = CurrentLanguage.Strings.PSM_Application_Output;
            this.langButton.Text = CurrentLanguage.Strings.Language;
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (notifier != null)
                notifier.WndProc(ref m);
        }

        private void appOutputBox_KeyDown(object sender, KeyEventArgs e)
        {
            love += (char)e.KeyValue;
            if (love.IndexOf("I LOVE VITACOM") != -1)
            {
                MessageBox.Show("I love you too! <3");
                love = "";
            }
        }

        private bool breakOut()
        {
            if (devices.Length == 0 || deviceid > devices.Length || !devices[deviceid].Online)
            {
                toggleActions();
                toggleDisconnectButtons();
                setStatusText(SelectLangString("Lost connection with device {0}!", "LostConnection"), deviceid.ToString());
                updateDeviceList(false);
                toggleDeviceList();
                return true;
            }

            return false;
        }

        private string getProgramFilesx86Path()
        {
            string win64path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
            if (string.IsNullOrEmpty(win64path)) return Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            else return win64path;
        }

        private RandomText GetRandomText()
        {
            try
            {
                string suffix = null;
                if (CurrentLanguage != null)
                    suffix = "_" + CurrentLanguage.Info.Code;

                return new RandomText("http://data.celcodioc.host22.com/vitacom/randomtextv2" + suffix);
            }
            catch
            {
                return new RandomText(8, SelectLangString("Could not download random text!", "CouldNotDownloadText"));
            }
        }

        private void langButton_Click(object sender, EventArgs e)
        {
            new LanguageSelectForm(this).ShowDialog(this);
        }

        private string SelectLangString(string defaultstring, string langstring)
        {
            if (CurrentLanguage == null) return defaultstring;
            else
            {
                FieldInfo info = CurrentLanguage.Strings.GetType().GetField(langstring);
                return (string)info.GetValue(CurrentLanguage.Strings);
            }
        }

        private void setStatusText(params object[] text)
        {
            string o = text[0].ToString();
            for (int i = 1; i < text.Length; i++)
                o = o.Replace("{" + (i - 1) + "}", text[i].ToString());
            statusText.Text = o;
        }

        private bool strArrContainsNull(params string[] str)
        {
            for (int i = 0; i < str.Length; i++)
                if (string.IsNullOrEmpty(str[i]) || str[i] == null) return true;
            return false;
        }

        private void toggleActions()
        {
            install_DoButton.Enabled = !install_DoButton.Enabled;
            uninstall_DeleteEverythingButton.Enabled = !uninstall_DeleteEverythingButton.Enabled;
            uninstall_DoButton.Enabled = !uninstall_DoButton.Enabled;
            launch_DoButton.Enabled = !launch_DoButton.Enabled;
        }

        //Only for packing!! simply fixes references right now
        private string convertAssembly(string inassembly, string outassembly)
        {
            Process dasm = Process.Start(ildasmpath, "/text \"" + TEMP_DIR + "\\Application\\" + inassembly + "\" /out=\"" + TEMP_DIR + "\\Application\\" + inassembly + ".il\"");
            dasm.WaitForExit();

            string ilfile;
            using (StreamReader ilreader = new StreamReader(TEMP_DIR + "\\Application\\" + inassembly + ".il"))
                ilfile = ilreader.ReadToEnd();

            ilfile = ilfile.Replace("pssapp", "app");

            if (ilfile.Contains("Sce.Pss"))
            {
                ilfile = ilfile.Replace("Sce.Pss", "Sce.PlayStation");
                ilfile.Insert(ilfile.IndexOf(IL_SEARCH_REFS), ".assembly extern System" +
"{" +
"  .publickeytoken = (79 43 9F FC 30 8A A6 A0 )                         // yC..0..." +
"  .ver 2:0:5:0" +
"}");
            }

            //this is rough
            string assemblyname = ilfile.Substring(ilfile.IndexOf(IL_SEARCH_NAME) + IL_SEARCH_NAME.Length);
            assemblyname = assemblyname.Substring(0, assemblyname.IndexOf("\r\n"));

            if (assemblyname.LastIndexOf('.') != -1)
                assemblyname = assemblyname.Substring(assemblyname.LastIndexOf('.') + 1);
            else
                assemblyname = assemblyname.Substring(assemblyname.LastIndexOf(' ') + 1);

            using (StreamWriter ilwriter = new StreamWriter(TEMP_DIR + "\\Application\\" + inassembly + ".il", false))
                ilwriter.Write(ilfile);

            Process asm = Process.Start(ilasmpath, "/quiet /nologo /text \"" + TEMP_DIR + "\\Application\\" + inassembly + ".il\" /res=\"" + inassembly + ".res\" /out=\"" + TEMP_DIR + "\\Application\\" + inassembly + "\"");
            asm.WaitForExit();

            if (inassembly != outassembly)
            {
                File.Move(TEMP_DIR + "\\Application\\" + inassembly, TEMP_DIR + "\\Application\\" + outassembly);
                File.Delete(TEMP_DIR + "\\Application\\" + inassembly);
            }

            //File.Delete(TEMP_DIR + "\\Application\\" + inassembly + ".il");
            File.Delete(TEMP_DIR + "\\Application\\" + inassembly + ".res");

            return assemblyname;
        }

        private void toggleDeviceList()
        {
            refreshButton.Enabled = !refreshButton.Enabled;
            deviceList.Enabled = !deviceList.Enabled;
        }

        private void toggleDisconnectButtons()
        {
            disconnectButton.Enabled = !disconnectButton.Enabled;
            killButton.Enabled = !killButton.Enabled;
        }

        private void toggleProgressForm()
        {
            this.Enabled = !this.Enabled;
            progressform.Visible = !progressform.Visible;
        }

        private void verifyWorkingDevices(ref Task tasktomonitor)
        {
            while (devices.Length > 0 && deviceid <= devices.Length && connection.IsValid && devices[deviceid].Online)
            {
                if (tasktomonitor.IsCompleted)
                    break;
                Thread.Sleep(250);
            }
            Thread.Sleep(150);
            if (!this.Enabled)
            {
                toggleProgressForm();
                disconnect(true);
                setStatusText(SelectLangString("The operation did not complete successfully!", "OpNotCompleted"));
            }
        }

        #endregion Misc

        #region Ugly Interface

        private void aboutButton_Click(object sender, EventArgs e)
        {
            new VCg_SplashForm().ShowDialog(this);
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void minimizeButton_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void titleBar_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
                contextmenu.Show(this, new Point(e.X, e.Y));
        }

        private void titleBarIcon_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                contextmenu.Show(this, new Point(titleBarIcon.Location.X, titleBarIcon.Location.Y + titleBarIcon.Size.Height));
        }

        private void titleBarText_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                NativeMethods.ReleaseCapture();
                NativeMethods.SendMessage(this.Handle, 0xA1, (IntPtr)2, (IntPtr)0);
            }
        }

        #endregion Ugly Interface
    }
}